package com.jvxb.manage.livable.service.dbDeploy.impl;

import com.jvxb.common.base.entity.WorkTask;
import com.jvxb.common.constants.DbConstants;
import com.jvxb.common.utils.DateUtil;
import com.jvxb.common.utils.IPUtil;
import com.jvxb.common.utils.WorkTaskUtil;
import com.jvxb.manage.livable.entity.DbDeployInfo;
import com.jvxb.manage.livable.entity.DbDeployInstance;
import com.jvxb.manage.livable.service.dbDeploy.MysqlDeployService;
import com.jvxb.manage.livable.vo.WorkOrderOperateVo;
import lombok.extern.log4j.Log4j2;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/**
 * @author jvxb
 * @since 2022-01-10
 */
@Log4j2
@Service(DbConstants.MYSQL + DbConstants.DEPLOY_SERVICE)
public class MysqlDeployServiceImpl extends BaseDeployServiceImpl implements MysqlDeployService {

    @Override
    @Async("asyncDeployExecutor")
    public void deploy(DbDeployInfo dbDeployInfo, WorkOrderOperateVo workOrderOperateVo) {
        log.info("开始部署" + dbDeployInfo.getDbType());
        try {
            //1）选择部署机器
            List<DbDeployInstance> deployInstances = getDbDeployInstances(dbDeployInfo);
            log.info(dbDeployInfo.getWorkOrderId() + "部署机器：" + deployInstances);
            //2）执行部署作业
            for (DbDeployInstance deployInstance : deployInstances) {
                executeDeployTask(deployInstance);
            }
            //3）初始化集群
            initMysqlCluster(dbDeployInfo, deployInstances);
            //4）部署成功后的操作：保存集群实例数据、修改工单状态等
            deploySuccess(dbDeployInfo, workOrderOperateVo);
        } catch (Exception e) {
            //部署失败后的操作
            log.error("MySQL执行部署异常，工单id=" + dbDeployInfo.getWorkOrderId(), e);
            deployFail(dbDeployInfo, e.getMessage());
            //此处有可能需要回滚实例，目前略过
        }
        log.info(dbDeployInfo.getDbType() + "部署完成");
    }

    private void executeDeployTask(DbDeployInstance deployInstance) throws Exception {
        //可使用（二进制包/docker）部署，此处统一使用docker快速部署。
        Integer mysqlDeployWorkId = Integer.valueOf(sysDictService.getUniValueByGroupAndKey("db_deploy", "mysql_deploy_work_id", "1"));
        String mysqlDeployCmd = getMysqlDeployCmd(deployInstance.getPort(), deployInstance.getVersion());
        WorkTask workTask = new WorkTask(mysqlDeployWorkId, deployInstance.getHost(), mysqlDeployCmd);
        WorkTaskUtil.run(workTask);
        //检测部署是否成功
        if (IPUtil.isPortUsed(deployInstance.getHost(), Integer.valueOf(deployInstance.getPort()))) {
            deployInstance.setDeployStatus(DbDeployInstance.DEPLOY_STATUS_SUCCESS);
        } else {
            deployInstance.setDeployStatus(DbDeployInstance.DEPLOY_STATUS_ERROR);
        }
        deployInstanceService.updateById(deployInstance);
    }

    private void initMysqlCluster(DbDeployInfo dbDeployInfo, List<DbDeployInstance> deployInstances) {
        //构建主从、创建账户等
        for (int i = 0; i < deployInstances.size(); i++) {
            if (i == 0) {
                deployInstances.get(i).setRole(DbConstants.ROLE_MASTER);
            } else {
                deployInstances.get(i).setRole(DbConstants.ROLE_SLAVE);
            }
            deployInstanceService.saveOrUpdate(deployInstances.get(i));
        }
    }

    private String getMysqlDeployCmd(String port, String version) {
        String confCmd = String.format("mkdir -p /docker/mysql/%s\n" +
                "chmod 755 /docker/mysql/%s\n" +
                "mkdir -p /docker/mysql/%s/conf\n" +
                "chmod 755 /docker/mysql/%s/conf\n" +
                "mkdir -p /docker/mysql/%s/log\n" +
                "chmod 777 /docker/mysql/%s/log\n" +
                "cat > /docker/mysql/%s/conf/my.cnf <<END\n" +
                "%s\n" +
                "END\n" +
                "chmod 644 /docker/mysql/%s/conf/my.cnf", port, port, port, port, port, getMysqlDefaultConf(), port);
        String deployCmd = String.format("docker run -p %s:3306 " +
                        "--name mysql%s " +
                        "--privileged=true " +
                        "--restart=unless-stopped " +
                        "-v /docker/mysql/%s/conf:/etc/mysql/conf.d " +
                        "-v /docker/mysql/%s/data:/var/lib/mysql " +
                        "-v /docker/mysql/%s/log:/var/log/mysql " +
                        "-e MYSQL_ROOT_PASSWORD=123456 " +
                        "-d mysql:%s ",
                port, port, port, port, port, version);
        return confCmd + "\n" + deployCmd;
    }

    private String getMysqlDefaultConf() {
        return "[client]\n" +
                "default-character-set = utf8mb4\n" +
                "[mysqld]\n" +
                "#\n" +
                "character_set_server = utf8mb4\n" +
                "collation-server = utf8mb4_general_ci\n" +
                "#\n" +
                "slow_query_log = 1\n" +
                "long_query_time = 1\n" +
                "slow_query_log_file = /var/log/mysql/mysql-slow.log\n" +
                "log_error = /var/log/mysql/mysql-err.log\n";
    }

}
